/***************************************************************************************

***************************************************************************************/

/*!
*************************************************************************************
* \file AEC.c
*
* \brief
*    AEC entropy coding routines
*
* \author
*    Main contributors (see contributors.h for copyright, address and affiliation details)
**************************************************************************************
*/

#include <stdlib.h>
#include <math.h>
#include <memory.h>
#include <assert.h>
#include "AEC.h"
#include "image.h"


int last_dquant = 0;
/***********************************************************************
* L O C A L L Y   D E F I N E D   F U N C T I O N   P R O T O T Y P E S
***********************************************************************
*/

void exp_golomb_encode_eq_prob( EncodingEnvironmentPtr eep_dp,
	unsigned int symbol,
	int k); 

void unary_bin_encode(EncodingEnvironmentPtr eep_frame,
	unsigned int symbol,
	BiContextTypePtr ctx,
	int ctx_offset);

void unary_bin_max_encode(EncodingEnvironmentPtr eep_frame,
	unsigned int symbol,
	BiContextTypePtr ctx,
	int ctx_offset,
	unsigned int max_symbol);

void unary_exp_golomb_level_encode( EncodingEnvironmentPtr eep_dp,
	unsigned int symbol,
	BiContextTypePtr ctx);

void unary_exp_golomb_mv_encode(EncodingEnvironmentPtr eep_dp,
	unsigned int symbol,
	BiContextTypePtr ctx,
	unsigned int max_bin);

extern int b8_ctr;      
void AEC_new_slice()
{
	last_dquant=0;
}


/*!
************************************************************************
* \brief
*    Check for available neighbouring blocks
*    and set pointers in current macroblock
************************************************************************
*/
void CheckAvailabilityOfNeighborsAEC()
{
    //added by lzhang 10.23
    int i, j;
    const int mb_width = img->width / MB_BLOCK_SIZE;
    const int mb_nr = img->current_mb_nr;
    Macroblock *currMB = &(img->mb_data[mb_nr]);
    int check_value;
    for (i = 0; i < 3; i++) {
        for (j = 0; j < 3; j++) {
            img->mb_data[mb_nr].mb_available[i][j] = NULL;
        }
    }
    img->mb_data[mb_nr].mb_available[1][1] = &(img->mb_data[mb_nr]);
    // Check MB to the left
    if (img->pix_x >= MB_BLOCK_SIZE) {
        int remove_prediction = currMB->slice_nr != img->mb_data[mb_nr - 1].slice_nr;
        if (!remove_prediction) {
            currMB->mb_available[1][0] = &(img->mb_data[mb_nr - 1]);
        }
    }
    // Check MB above
    check_value = (img->pix_y >= MB_BLOCK_SIZE);
    if (check_value)  {
        int remove_prediction = currMB->slice_nr != img->mb_data[mb_nr - mb_width].slice_nr;
        // upper blocks
        if (!remove_prediction) {
            currMB->mb_available[0][1] = &(img->mb_data[mb_nr - mb_width]);
        }
    }
    // Check MB left above
    if (img->pix_y >= MB_BLOCK_SIZE && img->pix_x >= MB_BLOCK_SIZE) {
        int remove_prediction = currMB->slice_nr != img->mb_data[mb_nr - mb_width - 1].slice_nr;
        if (!remove_prediction) {
            currMB->mb_available[0][0] = &(img->mb_data[mb_nr - mb_width - 1]);
        }
    }

    // Check MB right above
    if (img->pix_y >= MB_BLOCK_SIZE && img->pix_x < (img->width - MB_BLOCK_SIZE))
    {
        if (currMB->slice_nr == img->mb_data[mb_nr - mb_width + 1].slice_nr)
            currMB->mb_available[0][2] = &(img->mb_data[mb_nr - mb_width + 1]);
    }
    currMB->mb_available_left = currMB->mb_available[1][0];
    currMB->mb_available_up = currMB->mb_available[0][1];
    currMB->mbAddrA = mb_nr - 1;
    currMB->mbAddrB = mb_nr - img->PicWidthInMbs;
    currMB->mbAddrC = mb_nr - img->PicWidthInMbs + 1;
    currMB->mbAddrD = mb_nr - img->PicWidthInMbs - 1;

    currMB->mbAvailA = (currMB->mb_available[1][0] != NULL) ? 1 : 0;
    currMB->mbAvailB = (currMB->mb_available[0][1] != NULL) ? 1 : 0;
    currMB->mbAvailC = (currMB->mb_available[0][2] != NULL) ? 1 : 0;
    currMB->mbAvailD = (currMB->mb_available[0][0] != NULL) ? 1 : 0;
}

/*!
************************************************************************
* \brief
*    Allocation of contexts models for the motion info
*    used for arithmetic encoding
************************************************************************
*/
MotionInfoContexts* create_contexts_MotionInfo(void)
{
	MotionInfoContexts* enco_ctx;

	enco_ctx = (MotionInfoContexts*) calloc(1, sizeof(MotionInfoContexts) );
	if( enco_ctx == NULL )
		no_mem_exit("create_contexts_MotionInfo: enco_ctx");

	return enco_ctx;
}


/*!
************************************************************************
* \brief
*    Allocates of contexts models for the texture info
*    used for arithmetic encoding
************************************************************************
*/
TextureInfoContexts* create_contexts_TextureInfo(void)
{
	TextureInfoContexts*  enco_ctx;

	enco_ctx = (TextureInfoContexts*) calloc(1, sizeof(TextureInfoContexts) );
	if( enco_ctx == NULL )
		no_mem_exit("create_contexts_TextureInfo: enco_ctx");

	return enco_ctx;
}




/*!
************************************************************************
* \brief
*    Frees the memory of the contexts models
*    used for arithmetic encoding of the motion info.
************************************************************************
*/
void delete_contexts_MotionInfo(MotionInfoContexts *enco_ctx)
{
	if( enco_ctx == NULL )
		return;

	free( enco_ctx );

	return;
}

/*!
************************************************************************
* \brief
*    Frees the memory of the contexts models
*    used for arithmetic encoding of the texture info.
************************************************************************
*/
void delete_contexts_TextureInfo(TextureInfoContexts *enco_ctx)
{
	if( enco_ctx == NULL )
		return;

	free( enco_ctx );

	return;
}


/*!
**************************************************************************
* \brief
*    generates arithmetic code and passes the code to the buffer
**************************************************************************
*/
int writeSyntaxElement_AEC(SyntaxElement *se, DataPartition *this_dataPart)
{
	int curr_len;
	EncodingEnvironmentPtr eep_dp = &(this_dataPart->ee_AEC);

	curr_len = arienco_bits_written(eep_dp);

	// perform the actual coding by calling the appropriate method
	se->writing(se, eep_dp);

	if(se->type != SE_HEADER)
		this_dataPart->bitstream->write_flag = 1;

	return (se->len = (arienco_bits_written(eep_dp) - curr_len));
}

/*!
***************************************************************************
* \brief
*    This function is used to arithmetically encode the run length 
*    info to buffer
***************************************************************************
*/
void writeRunLengthInfo2Buffer_AEC(SyntaxElement *se, EncodingEnvironmentPtr eep_dp)
{  
	int symbol = se->value1;
	BiContextTypePtr pCTX;
	int ctx;
	pCTX = img->currentSlice->tex_ctx->one_contexts[0];
	ctx = 0;
	while( symbol >= 1 ) {
		symbol -= 1;
		biari_encode_symbol(eep_dp, 0, pCTX+ctx);
		ctx ++;
		if( ctx>=3 ) ctx=3;
	}
	biari_encode_symbol(eep_dp, 1, pCTX+ctx);
	return;
}

/*!
***************************************************************************
* \brief
*    This function is used to arithmetically encode the mb_skip_flag.
***************************************************************************
*/
void writeMB_skip_flagInfo_AEC(SyntaxElement *se, EncodingEnvironmentPtr eep_dp)
{
	int a,b,act_ctx;
	int bframe   = (img->type==B_IMG);
	MotionInfoContexts *ctx         = (img->currentSlice)->mot_ctx;
	Macroblock         *currMB      = &img->mb_data[img->current_mb_nr];
	int                curr_mb_type = se->value1;

	if (bframe)
	{
		if (currMB->mb_available_up == NULL)
			b = 0;
		else
			b = (currMB->mb_available_up->skip_flag==0 ? 0 : 1);
		if (currMB->mb_available_left == NULL)
			a = 0;
		else
			a = (currMB->mb_available_left->skip_flag==0 ? 0 : 1);

		act_ctx = 7 + a + b;

		if (se->value1==0 && se->value2==0) // DIRECT mode, no coefficients
			biari_encode_symbol (eep_dp, 1, &ctx->mb_type_contexts[2][act_ctx]);
		else
			biari_encode_symbol (eep_dp, 0, &ctx->mb_type_contexts[2][act_ctx]);   

		currMB->skip_flag = (se->value1==0 && se->value2==0)?0:1;
	}
	else
	{
		if (currMB->mb_available_up == NULL)
			b = 0;
		else
			b = (( (currMB->mb_available_up)->skip_flag != 0) ? 1 : 0 );
		if (currMB->mb_available_left == NULL)
			a = 0;
		else
			a = (( (currMB->mb_available_left)->skip_flag != 0) ? 1 : 0 );

		act_ctx = a + b;

		if (curr_mb_type==0) // SKIP
			biari_encode_symbol(eep_dp, 1,&ctx->mb_type_contexts[1][act_ctx]);
		else
			biari_encode_symbol(eep_dp, 0,&ctx->mb_type_contexts[1][act_ctx]);

		currMB->skip_flag = (curr_mb_type==0)?0:1;
	}
	se->context = act_ctx;

	return;
}

/*!
***************************************************************************
* \brief
*    This function is used to arithmetically encode the macroblock
*    transform type(2Nx2N/NxN) of a given MB.
***************************************************************************
*/
void writeMBTransType_AEC(SyntaxElement *se, EncodingEnvironmentPtr eep_dp)
{
    BiContextTypePtr pCTX = &(img->currentSlice)->tex_ctx->tu_size_context[0];
    biari_encode_symbol ( eep_dp, se->value1, pCTX);
}

/*!
***************************************************************************
* \brief
*    This function is used to arithmetically encode the macroblock
*    type info of a given MB.
***************************************************************************
*/

void writeMBPartTypeInfo_AEC(SyntaxElement *se, EncodingEnvironmentPtr eep_dp)
{
	int a, b;
	int act_ctx = 0;
	int act_sym;

	MotionInfoContexts *ctx         = (img->currentSlice)->mot_ctx;
	Macroblock         *currMB      = &img->mb_data[img->current_mb_nr];

	if( img->type==B_IMG ) {
		BiContextTypePtr pCTX = ctx->mb_type_contexts[2];

		if( currMB->mb_available[0][1]==NULL )
			b = 0;
		else
			b = (( (currMB->mb_available[0][1])->mb_type != 0) ? 1 : 0 );
		if (currMB->mb_available[1][0] == NULL)
			a = 0;
		else
			a = (( (currMB->mb_available[1][0])->mb_type != 0) ? 1 : 0 );
		act_ctx = a + b;
		se->context = act_ctx; // store context
			
		switch(currMB->mb_type){
		case 0:
		case 1:
			act_sym = currMB->mb_type; break; // 2Nx2N
		case 2:
			act_sym = 3; break; // 2NxN
		case 3:
			act_sym = 2; break; // Nx2N
		case 8:
			act_sym = 5; break; // NxN
		case 9:
			act_sym = 4; break; // I_MB
		default:
			printf("error input MB mode!\n");
			exit(0);
			break;
		}

		if( act_sym == 0 ) {
			biari_encode_symbol (eep_dp, 0, &ctx->mb_type_contexts[2][act_ctx]);
		}
		else {
			biari_encode_symbol (eep_dp, 1, &ctx->mb_type_contexts[2][act_ctx]);
			act_sym--;
			act_ctx = 3;
			while( act_sym>=1 ) {
				biari_encode_symbol (eep_dp, 0, pCTX + act_ctx );
				act_sym--;
				act_ctx++;
				if( act_ctx>=4 ) act_ctx=4;
			}
			biari_encode_symbol (eep_dp, 1, pCTX + act_ctx );
		}
	}

	if( img->type==P_IMG ) {
		BiContextTypePtr pCTX = ctx->mb_type_contexts[1];
		switch(currMB->mb_type){
		case 0:
		case 1:
			act_sym = 0; break; // 2Nx2N and SKIP, which are distinguished by the prediction mode
		case 2:
			act_sym = 2; break; // 2NxN
		case 3:
			act_sym = 1; break; // Nx2N
		case 8:
			act_sym = 4; break; // NxN
		case 9:
			act_sym = 3; break; // I_MB
		default:
			printf("error input MB mode!\n");
			exit(0);
			break;
		}

		act_ctx = 0;
		while( act_sym>=1 ) {
			biari_encode_symbol (eep_dp, 0, pCTX + act_ctx );
			act_sym--;
			act_ctx++;
			if( act_ctx>=3 ) act_ctx=3;
		}
		biari_encode_symbol (eep_dp, 1, pCTX + act_ctx );
	}
}

/*!
***************************************************************************
* \brief
*    This function is used to arithmetically encode the 8x8 block
*    type info
***************************************************************************
*/
void write_8x8_PredTypeInfo_AEC(SyntaxElement *se, EncodingEnvironmentPtr eep_dp)
{
	int act_ctx;
	int act_sym;
	int bframe=(img->type==B_IMG);

	MotionInfoContexts *ctx    = (img->currentSlice)->mot_ctx;
	BiContextTypePtr pCTX = ctx->b8_type_contexts[0];

	act_sym = se->value1;
	if( act_sym & 0x02 ) {
		biari_encode_symbol ( eep_dp, 1, pCTX );
		act_ctx = 3;
	}
	else {
		biari_encode_symbol ( eep_dp, 0, pCTX );
		act_ctx = 2;
	}
	biari_encode_symbol ( eep_dp, (unsigned char)(act_sym & 0x01), pCTX + act_ctx );
}

void write_other_PredTypeInfo_AEC(SyntaxElement *se, EncodingEnvironmentPtr eep_dp)
{
	int act_ctx;
	int act_sym;
	int bframe=(img->type==B_IMG);

	MotionInfoContexts *ctx    = (img->currentSlice)->mot_ctx;
	BiContextTypePtr pCTX = ctx->b8_type_contexts[0];

	act_sym = se->value1;

	if (act_sym == 0) {
		biari_encode_symbol ( eep_dp, 0, pCTX );
	} else {
		biari_encode_symbol ( eep_dp, 1, pCTX );
		act_ctx = 1;
		biari_encode_symbol ( eep_dp, (unsigned char)(act_sym & 0x01), pCTX + act_ctx );
	}
}

void MHMC_write_16x16_PredTypeInfo_AEC(SyntaxElement *se, EncodingEnvironmentPtr eep_dp)
{
	int act_ctx;
	int act_sym;

	MotionInfoContexts *ctx    = (img->currentSlice)->mot_ctx;
	BiContextTypePtr pCTX = ctx->b8_type_contexts[0];

	act_sym = se->value1;
	act_ctx = 0;
	if (act_sym == 0) {
		biari_encode_symbol ( eep_dp, 0, pCTX + act_ctx );
	} else {
		biari_encode_symbol ( eep_dp, 1, pCTX + act_ctx );
		act_ctx = 1;
		biari_encode_symbol ( eep_dp, (unsigned char)(act_sym & 0x01), pCTX + act_ctx );
	}
}

void MHMC_write_other_PredTypeInfo_AEC(SyntaxElement *se, EncodingEnvironmentPtr eep_dp)
{
	int act_ctx;
	int act_sym;

	MotionInfoContexts *ctx    = (img->currentSlice)->mot_ctx;
	BiContextTypePtr pCTX = ctx->b8_type_contexts[0];

	act_sym = se->value1;
	act_ctx = 0;
	biari_encode_symbol ( eep_dp, (unsigned char)(act_sym & 0x01), pCTX + act_ctx );
}

/*!
****************************************************************************
* \brief
*    This function is used to arithmetically encode a pair of
*    intra prediction modes of a given MB.
* \author
*    
****************************************************************************
*/
void writeIntraPredMode_AEC(SyntaxElement *se, EncodingEnvironmentPtr eep_dp)
{
	BiContextTypePtr pCTX;
	int ctx;
	int symbol = se->value1;
	int value = symbol;
	pCTX = img->currentSlice->tex_ctx->ipr_contexts;
	ctx = 0;
	while( symbol >= 1 ) 
	{
		symbol -= 1;
		biari_encode_symbol(eep_dp, 0, pCTX+ctx);
		ctx ++;
		if( ctx>=3 ) ctx=3;
	}
	if( value<4 )
		biari_encode_symbol(eep_dp, 1, pCTX+ctx);
}

void writeIntraSplit_AEC(SyntaxElement *se, EncodingEnvironmentPtr eep_dp)
{
    BiContextTypePtr pCTX;
    int symbol = se->value1;
    int value = symbol;
    pCTX = img->currentSlice->tex_ctx->qsplit_contexts;
    biari_encode_symbol(eep_dp, value, pCTX);
}

/*!
****************************************************************************
* \brief
*    This function is used to arithmetically encode the chroma
*    intra prediction mode of an 8x8 block
****************************************************************************
*/
void writeCIPredMode_AEC(SyntaxElement *se, EncodingEnvironmentPtr eep_dp)
{
	BiContextTypePtr pCTX;
	int ctx;
	int symbol = se->value1;
	int value = symbol;
	pCTX = img->currentSlice->tex_ctx->cipr_contexts;
	ctx = 0;
	while( symbol >= 1 ) 
	{
		symbol -= 1;
		biari_encode_symbol(eep_dp, 0, pCTX+ctx);
		ctx ++;
		if( ctx>=2 ) ctx=2;
	}
	if( value<3 )
		biari_encode_symbol(eep_dp, 1, pCTX+ctx);
}

/*!
****************************************************************************
* \brief
*    This function is used to arithmetically encode the coded
*    block pattern of a given delta quant.
****************************************************************************
*/
void writeDquant_AEC(SyntaxElement *se, EncodingEnvironmentPtr eep_dp)
{
	MotionInfoContexts *ctx = img->currentSlice->mot_ctx;

	int act_ctx;
	int act_sym;
	int dquant = se->value1;
	int sign=0;

	if (dquant <= 0)
		sign = 1;
	act_sym = abs(dquant) << 1;

	act_sym += sign;
	act_sym --;

	act_ctx = ( ( img->mb_data[img->current_mb_nr-1].delta_qp != 0) ? 1 : 0);

	if (act_sym==0)
	{
		biari_encode_symbol(eep_dp, 1, ctx->delta_qp_contexts + act_ctx );
	}
	else
	{
		biari_encode_symbol(eep_dp, 0, ctx->delta_qp_contexts + act_ctx);
		act_ctx=2;
		act_sym--;
		unary_bin_encode(eep_dp, act_sym,ctx->delta_qp_contexts+act_ctx,1);
	}
	last_dquant = dquant;
}

/*!
****************************************************************************
* \brief
*    This function is used to arithmetically encode the motion
*    vector data of a B-frame MB.
****************************************************************************
*/
void writeMVD_AEC(SyntaxElement *se, EncodingEnvironmentPtr eep_dp)
{
	int i = img->subblock_x;
	int j = img->subblock_y;
	int a, b;
	int act_ctx;
	unsigned int act_sym;
	int mv_pred_res;
	int mv_local_err;
	int mv_sign;
	int list_idx = se->value2 & 0x01; 
	int k = (se->value2>>1); 
	int mb_nr =img->current_mb_nr;
	//  short sig;
	unsigned int bin_idx=0;
	int exp_golomb_order=0;
	// int mbtype_a,mbtype_b,mbtype_c;//,mbtype_diff;
	int bin_table[5]={0,1,2,3,3};


	PixelPos block_a, block_b;

	MotionInfoContexts  *ctx    = img->currentSlice->mot_ctx;
	Macroblock          *currMB = &img->mb_data[img->current_mb_nr];

	getLuma8x8Neighbour(img->current_mb_nr, i, j, -1,  0, &block_a);
	getLuma8x8Neighbour(img->current_mb_nr, i, j,  0, -1, &block_b);


	if (block_b.available)
	{
		b = absm(img->mb_data[block_b.mb_addr].mvd[list_idx][block_b.y][block_b.x][k]);
	}
	else
		b=0;

	if (block_a.available)
	{
		a = absm(img->mb_data[block_a.mb_addr].mvd[list_idx][block_a.y][block_a.x][k]);
	}
	else
		a = 0;


	if ((mv_local_err=a)<2)
		act_ctx = 0;
	else if (mv_local_err<16)
		act_ctx = 1;
	else
		act_ctx = 2;


	mv_pred_res = se->value1;  
	se->context = act_ctx;
	act_sym = absm(mv_pred_res);


	if (act_sym< 3) // 0, 1, 2
	{
		if (act_sym == 0)
			biari_encode_symbol(eep_dp, 0, &ctx->mv_res_contexts[k][act_ctx]);
		else if (act_sym == 1)
		{
			biari_encode_symbol(eep_dp, 1, &ctx->mv_res_contexts[k][act_ctx]);
			biari_encode_symbol(eep_dp, 0, &ctx->mv_res_contexts[k][3]);
		}
		else if (act_sym == 2)
		{
			biari_encode_symbol(eep_dp, 1, &ctx->mv_res_contexts[k][act_ctx]);
			biari_encode_symbol(eep_dp, 1, &ctx->mv_res_contexts[k][3]);
			biari_encode_symbol(eep_dp, 0, &ctx->mv_res_contexts[k][4]);
		}

	}
	else
	{
		if (act_sym% 2==1) //odds >3
		{
			biari_encode_symbol(eep_dp, 1, &ctx->mv_res_contexts[k][act_ctx]);
			biari_encode_symbol(eep_dp, 1, &ctx->mv_res_contexts[k][3]);
			biari_encode_symbol(eep_dp, 1, &ctx->mv_res_contexts[k][4]);
			biari_encode_symbol(eep_dp, 0, &ctx->mv_res_contexts[k][5]);
			act_sym = (act_sym - 3)/2;

		}
		else //even >3
		{
			biari_encode_symbol(eep_dp, 1, &ctx->mv_res_contexts[k][act_ctx]);
			biari_encode_symbol(eep_dp, 1, &ctx->mv_res_contexts[k][3]);
			biari_encode_symbol(eep_dp, 1, &ctx->mv_res_contexts[k][4]);
			biari_encode_symbol(eep_dp, 1, &ctx->mv_res_contexts[k][5]);
			act_sym = (act_sym - 4)/2;
		}
		// exp_golomb part
		while(1)
		{
			if (act_sym >= (unsigned int)(1<<exp_golomb_order))   
			{
				biari_encode_symbol_eq_prob(eep_dp,0);
				act_sym = act_sym - (1<<exp_golomb_order);
				exp_golomb_order++;
			}
			else                  
			{
				biari_encode_symbol_eq_prob(eep_dp,1);
				while (exp_golomb_order--)//next binary part
				{
					biari_encode_symbol_eq_prob(eep_dp,(unsigned char)((act_sym>>exp_golomb_order)&1));
				}
				break;
			}
		}
	}

	if (mv_pred_res!=0)
	{	  
		mv_sign= (mv_pred_res>=0) ? 0:1;
		biari_encode_symbol_eq_prob(eep_dp,(unsigned char) mv_sign);
	}
}
/*!
****************************************************************************
* \brief
*    This function is used to arithmetically encode the coded
*    block pattern of an 8x8 block
****************************************************************************
*/
void writeCBP_BIT_AEC (int b8, int b4, int bit, int cbp, Macroblock* currMB, EncodingEnvironmentPtr eep_dp)
{
	int a, b;

    int b8x = b8 % 2;
    int b8y = b8 / 2;
    int b4x = b4 % 2;
    int b4y = b4 / 2;

    int b8_up = 0xF, b8_left = 0xF; // cbp in 8x8 block, 4bit
    int b8_cbp = cbp >> (4 * b8);

    // 1st. get 8x8 neighbour's cbp
    if (b8y == 0) {
        if (currMB->mb_available_up != NULL) {
            b8_up &= ((currMB->mb_available_up)->cbp) >> (4 * (2 + b8x));
        }
    } else {
        b8_up &= cbp >> (4 * b8x);
    }

    if (b8x == 0) {
        if (currMB->mb_available_left != NULL) {
            b8_left &= ((currMB->mb_available_left)->cbp) >> (4 * (2 * b8y + 1)); 
        }
    } else {
        b8_left &= cbp >> (4 * 2 * b8y);
    }

    // 2nd. get a & b
    if (b4y == 0) {
        b = (b8_up & (1 << (2 + b4x))) == 0 ? 1 : 0;   //VG-ADD
    } else {
        b = (b8_cbp & (1 << b4x)) == 0 ? 1 : 0;
    }

    if (b4x == 0) {
        a = (b8_left & (1 << (2 * b4y + 1))) == 0 ? 1 : 0; //VG-ADD
    } else {
        a = (b8_cbp & (1 << (2 * b4y))) == 0 ? 1 : 0;
    }

	//===== WRITE BIT =====
	biari_encode_symbol (eep_dp, (unsigned char) bit, img->currentSlice->tex_ctx->cbp_contexts[0] + a+2*b);
}

/*!
****************************************************************************
* \brief
*    This function is used to arithmetically encode the coded
*    block pattern of a macroblock
***************************************************************************
*/
void writeCBP_AEC(SyntaxElement *se, EncodingEnvironmentPtr eep_dp)
{
	TextureInfoContexts *ctx = img->currentSlice->tex_ctx;
	Macroblock *currMB = &img->mb_data[img->current_mb_nr];

	int curr_cbp_ctx;
	int cbp = se->value1; // symbol to encode
	int cbp_bit;
	int b8, b4;
    
    // luma
    if (currMB->trans_type == TRANS_2Nx2N) {
        writeCBP_BIT_AEC(0, 0, (cbp & (0xFFFF)) != 0, cbp, currMB, eep_dp);
    } else {
        for (b8 = 0; b8 < 4; b8++) {
            if (currMB->trans_split[b8]) {
                for (b4 = 0; b4 < 4; b4++) {
                    writeCBP_BIT_AEC(b8, b4, (cbp&(0x1 << (4 * b8 + b4))) != 0, cbp, currMB, eep_dp);
                }
            } else {
                writeCBP_BIT_AEC(b8, 0, (cbp&(0xF << (4 * b8))) != 0, cbp, currMB, eep_dp);
            }
        }
    }

    // chroma
	cbp_bit = (cbp > 0xFFFF ) ? 1 : 0;
	curr_cbp_ctx = 0;
	biari_encode_symbol(eep_dp, (unsigned char) cbp_bit, ctx->cbp_contexts[1] + curr_cbp_ctx );
	if (cbp > 0xFFFF) {
		cbp_bit = (cbp >= 0xFF0000 ) ? 1 : 0;          //changed by lzhang
		curr_cbp_ctx = 1;
		biari_encode_symbol(eep_dp, (unsigned char) cbp_bit, ctx->cbp_contexts[1] + curr_cbp_ctx );
		if(cbp < 0xFF0000)
		{
			cbp_bit = ((cbp>>16) == 0xF0) ? 1 : 0;
			biari_encode_symbol(eep_dp, (unsigned char) cbp_bit, ctx->cbp_contexts[1] + curr_cbp_ctx );
		}
	}

	if (!cbp) {
		last_dquant=0;
	}

}

/*!
****************************************************************************
* \brief
*    Write coefficients
****************************************************************************
*/
int DCT_Pairs = 0;
int DCT_Level[257]={0};
int DCT_Run[257]={0};
int Pair_Pos = 0;
const int T_Chr[5] = { 0,1,2,4,3000};
int DCT_Block_Size = 0;

void writeRunLevel_AEC_Ref( SyntaxElement *se, EncodingEnvironmentPtr eep_dp )
{
	int pairs=0, rank=0, pos=0;
	int Run=0, Level=0, absLevel=0, symbol=0;
    int coef_num = DCT_Block_Size * DCT_Block_Size;
    int Primary_shift_offset;

    switch (DCT_Block_Size) {
    case 4:
        Primary_shift_offset = 0;
        break;
    case 8:
        Primary_shift_offset = 2;
        break;
    case 16:
        Primary_shift_offset = 4;
        break;
    }

	//! Accumulate Run-Level Information
	if( se->value1!=0 ) {
		DCT_Level[Pair_Pos] = se->value1;
		DCT_Run[Pair_Pos]   = se->value2;
		Pair_Pos ++;
		DCT_Pairs ++;
		return;
	}
	if( DCT_Pairs>0 ) {
		BiContextType (*Primary)[NUM_MAP_CTX];
		BiContextTypePtr pCTX;
		BiContextTypePtr pCTX2;
		//Macroblock   *currMB      = &img->mb_data[img->current_mb_nr];
		int ctx=0, offset=0, ctx2=0;

		if( se->context==LUMA_8x8 ) {
			Primary = img->currentSlice->tex_ctx->map_contexts;
		}
		else {	
			Primary = img->currentSlice->tex_ctx->last_contexts;
		}
		pairs = DCT_Pairs;
		rank = 0;
		pos  = 0;
		for( ; pairs>=0; pairs-- ) {
			if( pairs==0 ) {
				Level = 0;
				Run = 0;
			}
			else {
				Level = DCT_Level[pairs-1];
				Run = DCT_Run[pairs-1];
			}
			absLevel = abs(Level);
			pCTX = Primary[rank];
			//! EOB
			if( rank>0) {
				pCTX2 = Primary[5+(pos>>(3+Primary_shift_offset))];
				ctx2 = (pos>>1) & 0x0f;
				ctx = 0;
				if( absLevel==0 ) {
					//biari_encode_symbol( eep_dp, 1, pCTX+ctx );
					//biari_encode_symbol( eep_dp, 1, pCTX2+ctx2 );
					biari_encode_symbolW( eep_dp, 1, pCTX+ctx, pCTX2+ctx2 );
					break;
				}
				else {
					//biari_encode_symbol( eep_dp, 0, pCTX+ctx );
					//biari_encode_symbol( eep_dp, 0, pCTX2+ctx2 );
					biari_encode_symbolW( eep_dp, 0, pCTX+ctx, pCTX2+ctx2 );
				}
			}
			//! Level
			symbol = absLevel-1;
			ctx = 1;
			while( symbol>=1 ) {
				symbol -= 1;
				biari_encode_symbol( eep_dp, 0, pCTX+ctx );
				//biari_encode_zero( eep_dp, pCTX+ctx );
				ctx ++;
				if( ctx>=2 ) ctx =2;
			}
			biari_encode_symbol( eep_dp, 1, pCTX+ctx );
			//enbac1(ctx,currBacState,currBitStream);
			//! Sign
			if( Level<0 ) {
				biari_encode_symbol_eq_prob( eep_dp, 1);
				//enbac_h1(currBacState,currBitStream);
			}
			else {
				biari_encode_symbol_eq_prob( eep_dp, 0);
				//enbac_h0(currBacState,currBitStream);
			}
			//! Run
			if( absLevel==1 ) { 
				offset = 4;
			}
			else {
				offset = 6;
			}
			symbol = Run;
			ctx = 0;
			while( symbol>=1 ) {
				symbol -= 1;
				biari_encode_symbol( eep_dp, 0, pCTX + ctx + offset );
				//biari_encode_zero( eep_dp, pCTX + ctx + offset );
				ctx ++;
				if( ctx>=1 ) ctx =1;
			}
			//enbac1(ctx+offset,currBacState,currBitStream);
			biari_encode_symbol( eep_dp, 1, pCTX + ctx + offset);
			//! Update Rank
			if( absLevel>T_Chr[rank] ) {
				if( absLevel<=2 )
					rank = absLevel;
				else if( absLevel<=4 )
					rank = 3;
				else
					rank = 4;
			}
			//! Update position
			pos += (Run+1);
			if( pos>=coef_num ) pos = coef_num - 1;
		}
	}
	//--- Reset Counters ---
	Pair_Pos = DCT_Pairs = 0; 
}







/*!
************************************************************************
* \brief
*    Unary binarization and encoding of a symbol by using
*    one or two distinct models for the first two and all
*    remaining bins
*
************************************************************************/
void unary_bin_encode(EncodingEnvironmentPtr eep_dp,
	unsigned int symbol,
	BiContextTypePtr ctx,
	int ctx_offset)
{
	unsigned int l;
	BiContextTypePtr ictx;

	if (symbol==0)
	{
		biari_encode_symbol(eep_dp, 1, ctx );
		return;
	}
	else
	{
		biari_encode_symbol(eep_dp, 0, ctx );
		l=symbol;
		ictx=ctx+ctx_offset;
		while ((--l)>0)
			biari_encode_symbol(eep_dp, 0, ictx);
		biari_encode_symbol(eep_dp, 1, ictx);
	}
	return;
}

/*!
************************************************************************
* \brief
*    Unary binarization and encoding of a symbol by using
*    one or two distinct models for the first two and all
*    remaining bins; no terminating "0" for max_symbol
*    (finite symbol alphabet)
************************************************************************
*/
void unary_bin_max_encode(EncodingEnvironmentPtr eep_dp,
	unsigned int symbol,
	BiContextTypePtr ctx,
	int ctx_offset,
	unsigned int max_symbol)
{
	unsigned int l;
	BiContextTypePtr ictx;

	if (symbol==0)
	{
		biari_encode_symbol(eep_dp, 0, ctx );
		return;
	}
	else
	{
		biari_encode_symbol(eep_dp, 1, ctx );
		l=symbol;
		ictx=ctx+ctx_offset;
		while ((--l)>0)
			biari_encode_symbol(eep_dp, 1, ictx);
		if (symbol<max_symbol)
			biari_encode_symbol(eep_dp, 0, ictx);
	}
	return;
}



/*!
************************************************************************
* \brief
*    Exp Golomb binarization and encoding
************************************************************************
*/
void exp_golomb_encode_eq_prob( EncodingEnvironmentPtr eep_dp,
	unsigned int symbol,
	int k) 
{
	while(1)
	{
		if (symbol >= (unsigned int)(1<<k))   
		{
			biari_encode_symbol_eq_prob(eep_dp, 1);   //first unary part
			symbol = symbol - (1<<k);
			k++;
		}
		else                  
		{
			biari_encode_symbol_eq_prob(eep_dp, 0);   //now terminated zero of unary part
			while (k--)                               //next binary part
				biari_encode_symbol_eq_prob(eep_dp, (unsigned char)((symbol>>k)&1)); 
			break;
		}
	}

	return;
}

/*!
************************************************************************
* \brief
*    Exp-Golomb for Level Encoding
*
************************************************************************/
void unary_exp_golomb_level_encode( EncodingEnvironmentPtr eep_dp,
	unsigned int symbol,
	BiContextTypePtr ctx)
{
	unsigned int l,k;
	unsigned int exp_start = 13; // 15-2 : 0,1 level decision always sent

	if (symbol==0)
	{
		biari_encode_symbol(eep_dp, 0, ctx );
		return;
	}
	else
	{
		biari_encode_symbol(eep_dp, 1, ctx );
		l=symbol;
		k=1;
		while (((--l)>0) && (++k <= exp_start))
			biari_encode_symbol(eep_dp, 1, ctx);
		if (symbol < exp_start) biari_encode_symbol(eep_dp, 0, ctx);
		else exp_golomb_encode_eq_prob(eep_dp,symbol-exp_start,0);
	}
	return;
}



/*!
************************************************************************
* \brief
*    Exp-Golomb for MV Encoding
*
************************************************************************/
void unary_exp_golomb_mv_encode(EncodingEnvironmentPtr eep_dp,
	unsigned int symbol,
	BiContextTypePtr ctx,
	unsigned int max_bin)
{
	unsigned int l,k;
	unsigned int bin=1;
	BiContextTypePtr ictx=ctx;
	unsigned int exp_start = 8; // 9-1 : 0 mvd decision always sent

	if (symbol==0)
	{
		biari_encode_symbol(eep_dp, 0, ictx );
		return;
	}
	else
	{
		biari_encode_symbol(eep_dp, 1, ictx );
		l=symbol;
		k=1;
		ictx++;
		while (((--l)>0) && (++k <= exp_start))
		{
			biari_encode_symbol(eep_dp, 1, ictx  );
			if ((++bin)==2) ictx++;
			if (bin==max_bin) ictx++;
		}
		if (symbol < exp_start) biari_encode_symbol(eep_dp, 0, ictx);
		else exp_golomb_encode_eq_prob(eep_dp,symbol-exp_start,3);
	}
	return;
}

void write_Reffrm_AEC(SyntaxElement *se, EncodingEnvironmentPtr eep_dp)
{
  int act_ctx = 0;
  int act_sym;
  int bframe   = (img->type==B_IMG);
  int mode_sym = 0;

  MotionInfoContexts *ctx         = (img->currentSlice)->mot_ctx;
  Macroblock         *currMB      = &img->mb_data[img->current_mb_nr];
  int                curr_mb_type = se->value1; 

    
    BiContextTypePtr pCTX = img->currentSlice->tex_ctx->one_contexts[1];//ctx->mb_type_contexts[1];

    act_sym = se->value1;
     act_sym = curr_mb_type;
    act_ctx = 0;

    while( act_sym>=1 ) 
    {
        biari_encode_symbol (eep_dp, 0, pCTX + act_ctx );
        act_sym--;
        act_ctx++;
       // if( act_ctx>=4 ) act_ctx=4;
        if( act_ctx>=(input->number_reference_frame-1) ) act_ctx=(input->number_reference_frame-1);

    }

    biari_encode_symbol (eep_dp, 1, pCTX + act_ctx );
}